import { Md5 } from "ts-md5";

import { MongodbClient } from "../lib/db.client.mongodb";
import { PgClient } from "../lib/db.client.pg";

import { ObjectId } from "mongodb";

import { ENUM_USER, RefUserSub, Sortable, User, UserPassword } from "qqlx-core";
import {
  getConditionMatchStrOrs,
  getConditionMatchBool,
  getConditionSort,
  UserSchema,
  getConditionMatchStr,
  UserPasswordSchema,
  RefUserSubSchema,
  toString,
} from "qqlx-cdk";

import { Corp, User as OldUser, UserWeChat as OldUserWeChat, Order } from "../../../qqlx.old/qqlx-core";
import { UserDao, UserPasswordDao, RefUserSubDao } from "../dao/stream/nest.user";

export async function doUserInsert(adminUserId: string, masterUserId: string, masterCorpId: string) {
  const mongodbClient = new MongodbClient("mongodb://localhost:27017/qqlx");
  const pgClient = new PgClient("127.0.0.1", "5432", "production", "postgres", "postgres");

  console.group("\n即将迁移：mongo用户数据");
  const _id_to_user_map = new Map<OldUser["_id"], User>();
  const stat = { before: 0, wanner: 0, now: 0 };

  try {
    await mongodbClient.start();
    const MongoUser = mongodbClient.getCollection("users");
    const MongoUserWeChat = mongodbClient.getCollection("userwechats");
    const MongoCorp = mongodbClient.getCollection("corps");
    const MongoOrder = mongodbClient.getCollection("orders");

    // 关键店铺 > 订单 > 联系人
    const mongo_master_corp = (await MongoCorp.findOne<Corp>({ _id: masterCorpId as unknown as ObjectId })) as Corp;
    if (mongo_master_corp.userId !== masterUserId) throw new Error(`公司 ${mongo_master_corp.name} 的负责人不匹配`);
    const mongo_corp_order_list = await MongoOrder.find<Order>({ corpId: mongo_master_corp._id as unknown as ObjectId }).toArray();
    const mongo_order_creatorids = mongo_corp_order_list.map((o) => o.creatorId);
    const mongo_order_manager_ids = mongo_corp_order_list.map((o) => o.managerId);
    const mongo_order_accounter_ids = mongo_corp_order_list.map((o) => o.accounterId);
    const order_user_ids = Array.from(new Set([...mongo_order_creatorids, ...mongo_order_manager_ids, ...mongo_order_accounter_ids]))
      .filter(Boolean)
      .filter((id) => ![adminUserId, masterUserId].includes(id));

    // 关键用户
    const oids = [adminUserId, masterUserId, ...order_user_ids] as unknown as ObjectId[];
    const mongo_user_wechat_list = await MongoUserWeChat.find<OldUserWeChat>({ userId: { $in: oids } }).toArray();
    const mongo_user_list = await MongoUser.find<OldUser>({ _id: { $in: oids } }).toArray();
    const mongo_user_map = new Map<OldUser["_id"], { old: OldUser; name: string }>();
    for (const user of mongo_user_list) {
      const name = mongo_user_wechat_list.find((c) => c.userId === user._id)?.nickname || "";
      mongo_user_map.set(toString(user._id), { old: user, name });
    }
    stat.wanner = mongo_user_map.size;

    // ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░░░░▄▄▄▄▄▄░░░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░░▄█▀▀▀▀▀█▄░░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░▄█░░▄▄▄░░█▄░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░█░░█▀▀█░░█░░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░█░░█▀▀█░░█░░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░█░░█▄▄█░░█░░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░▀▄▀▄▄▄▄▄▀▄▀░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░

    const pgClientIns = await pgClient.start();
    const userDao = new UserDao(pgClientIns.getRepository<User>(UserSchema));
    const userPasswordDao = new UserPasswordDao(pgClientIns.getRepository<UserPassword>(UserPasswordSchema));
    const refUserSubDao = new RefUserSubDao(pgClientIns.getRepository<RefUserSub>(RefUserSubSchema));
    const pgCount = await userDao.count([getConditionMatchBool("isDisabled", false)]);
    stat.before = pgCount;

    // ======
    // ======
    // ======
    // ======
    // ======
    // ======

    // 准备超级管理员
    const { firstMatch } = await userDao.queryMatch([getConditionMatchStr("desc", adminUserId)]);
    if (firstMatch) {
      const oldSuperUserName = mongo_user_map.get(adminUserId)!.name;
      console.log("超级管理员（已经存在）", oldSuperUserName, firstMatch.desc === adminUserId);
      _id_to_user_map.set(adminUserId, firstMatch);
    } else {
      const oldSuperUser = mongo_user_map.get(adminUserId)!.old;
      const oldSuperUserAvatar = mongo_user_wechat_list.find((c) => c.userId === adminUserId)?.avator || "";
      const oldSuperUserName = mongo_user_map.get(adminUserId)!.name;
      const superUser = getUserFromOld(oldSuperUser, oldSuperUserName, oldSuperUserAvatar);

      superUser.type = ENUM_USER.PRIMARY;
      const created = await userDao.insertOne(superUser);
      await userPasswordDao.insertOne(insertUserPwd(created));

      _id_to_user_map.set(adminUserId, created);
      console.log("超级管理员", oldSuperUserName, created.desc === adminUserId);
    }

    const {
      list: [first],
    } = await userDao.page({
      page: { page: 1, pageSize: 1 },
      conditionList: [getConditionSort("timeCreate", Sortable.ASC)],
    });
    if (first?.desc !== adminUserId) throw new Error(`超级管理员异常 ?= ${first?.desc}`);

    // ======
    // ======
    // ======
    // ======
    // ======
    // ======

    // 准备主账号
    const condis1 = [getConditionMatchBool("isDisabled", false), getConditionMatchStr("desc", masterUserId)];
    const userCount1 = await userDao.queryAll(condis1);
    if (userCount1.total === 0) {
      const oldMaster = mongo_user_map.get(masterUserId)!.old;
      const oldMasterName = mongo_user_map.get(masterUserId)!.name;
      const oldMasterAvatar = mongo_user_wechat_list.find((c) => c.userId === masterUserId)?.avator || "";
      const oldMasterUser = getUserFromOld(oldMaster, oldMasterName, oldMasterAvatar);

      oldMasterUser.type = ENUM_USER.PRIMARY;
      const created = await userDao.insertOne(oldMasterUser);
      await userPasswordDao.insertOne(insertUserPwd(created));

      console.log(oldMasterName, "Id校验", masterUserId === created.desc);
      _id_to_user_map.set(masterUserId, created);
    } else {
      userCount1.list.map((userNew) => {
        const oldMasterName = mongo_user_map.get(userNew.desc)!.name;
        console.log(oldMasterName, "Id校验", masterUserId === userNew.desc);
        _id_to_user_map.set(userNew.desc, userNew);
      });
    }

    // 准备辅助账号
    const masterNew = _id_to_user_map.get(masterUserId)!;
    const condis2 = [getConditionMatchBool("isDisabled", false), getConditionMatchStrOrs("desc", order_user_ids as unknown as string[])];
    const userCount2 = await userDao.queryAll(condis2);
    if (userCount2.total === 0) {
      for (const oldUserId of order_user_ids) {
        const oldUser = mongo_user_map.get(oldUserId)!.old;
        const oldUserName = mongo_user_map.get(oldUserId)!.name;
        const oldUserAvatar = mongo_user_wechat_list.find((c) => c.userId === oldUserId)?.avator || "";
        const pg_user = getUserFromOld(oldUser, oldUserName, oldUserAvatar);

        pg_user.type = ENUM_USER.DERIVED;
        const pg_user_created = await userDao.insertOne(pg_user);
        await userPasswordDao.insertOne(insertUserPwd(pg_user_created));
        await refUserSubDao.insertOne(insertUserSubLink(masterNew.uuid32, pg_user_created));

        _id_to_user_map.set(oldUser._id, pg_user_created);
        console.log(oldUserName, "Id校验", oldUser._id === pg_user_created.desc);
      }
    } else {
      userCount2.list.map((userNew) => {
        const oldUserName = mongo_user_map.get(userNew.desc)!.name;
        console.log(oldUserName, "Id校验", userNew.desc);
        _id_to_user_map.set(userNew.desc, userNew);
      });
    }

    // ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░░░░▄▄▄▄▄▄░░░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░░▄█▀▀▀▀▀█▄░░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░▄█░░▄▄▄░░█▄░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░█░░█▀▀█░░█░░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░█░░█▀▀█░░█░░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░█░░█▄▄█░░█░░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░▀▄▀▄▄▄▄▄▀▄▀░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░

    const pgCountFinal = await userDao.count([getConditionMatchBool("isDisabled", false)]);
    stat.now = pgCountFinal;

    console.log(`🔴迁移前 >> 迁移后 / stream_user`, stat.before, stat.now);
    console.log(`期望`, stat.wanner);
    console.log(`📉误差`, stat.now - stat.before - stat.wanner);
    console.groupEnd();
    console.log("====================================");

    return { _id_to_user_map };
  } finally {
    await pgClient.stop();
    await mongodbClient.stop();
  }
}

function getUserFromOld(old: OldUser, name: string, avatar: string) {
  const user: User = new UserSchema();
  user.nickname = name;
  user.desc = old._id.toString();
  user.avatar = avatar;
  user.timeCreate = old.timeCreate.toString();
  user.timeUpdate = old.timeUpdate.toString();
  return user;
}

function insertUserPwd(user: User) {
  const schema: UserPassword = new UserPasswordSchema();
  schema.refOwnerUUid32 = user.uuid32;
  schema.accountNumber = user.desc;

  const password = new Md5().appendStr([user.desc, "QQLX"].join(";")).end() as string;
  const password2 = new Md5().appendStr([password, "qqlx_pwd"].join(";")).end() as string;
  schema.password = password2;

  schema.timeCreate = user.timeCreate;
  schema.timeUpdate = user.timeUpdate;
  return schema;
}

function insertUserSubLink(masterId: string, subUser: User) {
  const schema: RefUserSub = new RefUserSubSchema();
  schema.refOwnerUUid32 = masterId;
  schema.refCreatorId = subUser.uuid32;

  schema.timeCreate = subUser.timeCreate;
  schema.timeUpdate = subUser.timeUpdate;
  return schema;
}
